public without sharing class AccountHandler 
{
	public static Boolean bIsApexTest {get;set;}
	public static void preProcessAccounts(List<Account> accounts)
	{
		if(bIsApexTest == null) bIsApexTest = false;
		for(Account account:accounts)
		{
			// Email
			account.Email_indexed__c = account.PersonEmail;
			if(account.PersonEmail != null)
			{
				account.Email_indexed__c = String.valueOf(account.PersonEmail).replaceAll('\\s', '');
			}
			// Mobile Phone
			String strCleanPersonMobilePhone = '';
			account.Mobile_indexed__c = account.PersonMobilePhone;
			if(account.PersonMobilePhone != null)
			{
				strCleanPersonMobilePhone = String.valueOf(account.PersonMobilePhone).replaceAll('[a-zA-Z]', '');
				strCleanPersonMobilePhone = strCleanPersonMobilePhone.replaceAll('\\s', '');	
				strCleanPersonMobilePhone = strCleanPersonMobilePhone.replaceAll('-', '');
				strCleanPersonMobilePhone = strCleanPersonMobilePhone.replaceAll('\\+', '');
				strCleanPersonMobilePhone = strCleanPersonMobilePhone.replaceAll('\\.', '');
				if(strCleanPersonMobilePhone.trim() != '')
				{
					account.Mobile_indexed__c = strCleanPersonMobilePhone;
				}				
			}
			// Phone
			String strCleanPhone = '';
			account.Phone_indexed__c = account.Phone;
			if(account.Phone != null)
			{
				strCleanPhone = String.valueOf(account.Phone).replaceAll('[a-zA-Z]', '');
				strCleanPhone = strCleanPhone.replaceAll('\\s', '');	
				strCleanPhone = strCleanPhone.replaceAll('-', '');
				strCleanPhone = strCleanPhone.replaceAll('\\+', '');
				strCleanPhone = strCleanPhone.replaceAll('\\.', '');
				if(strCleanPhone.trim() != '')
				{
					account.Phone_indexed__c = strCleanPhone;
				}				
			}
			// Duplication Flag Logic implemented on Warranty Page Controller 
			// Flat Number
			// Floor Number
			// Tower/Block Number		
		}		
	}
	public static void validateAccounts(List<Account> listNewAccounts)
	{
		String strDebug = '';
		Set<Id> setRecordIds = new Set<Id>();
		Set<String> setEmails = new Set<String>();
		Set<String> setMobilePhones = new Set<String>();
		Set<String> setPhones = new Set<String>();	
		Set<String> setTempEmails = new Set<String>();
		Set<String> setTempMobilePhones = new Set<String>();
		Set<String> setTempPhones = new Set<String>();
		for(Account account:listNewAccounts)
		{
			if(account.Email_indexed__c != null && account.PersonEmail != null)
			{
				setEmails.add(account.Email_indexed__c);
			}
			if(account.Mobile_indexed__c != null && account.PersonMobilePhone != null)
			{
				setMobilePhones.add(account.Mobile_indexed__c);
			}
			if(account.Phone_indexed__c != null && account.Phone != null)
			{
				setPhones.add(account.Phone_indexed__c);
			}
			
			if(account.Email_indexed__c != null && account.PersonEmail != null)
			{
				if(!setTempEmails.contains(account.Email_indexed__c))
				{
					setTempEmails.add(account.Email_indexed__c);
				}
				else
				{
					account.Duplicate__c = true;
					account.Duplicate_Reason__c = 'Email duplicate in batch record';
				}
			}
			if(account.Mobile_indexed__c != null && account.PersonMobilePhone != null)
			{
				if(!setTempMobilePhones.contains(account.Mobile_indexed__c))
				{
					setTempMobilePhones.add(account.Mobile_indexed__c);
				}
				else
				{
					account.Duplicate__c = true;
					account.Duplicate_Reason__c = 'Mobile Phone duplicate in batch record';
				}
			}
			if(account.Phone_indexed__c != null && account.Phone != null)
			{
				if(!setTempPhones.contains(account.Phone_indexed__c))
				{
					setTempPhones.add(account.Phone_indexed__c);
				}
				else
				{
					account.Duplicate__c = true;
					account.Duplicate_Reason__c = 'Phone duplicate in batch record';
				}
			}
						
			if(account.Id != null) 
			{
				setRecordIds.add(account.Id);
			}								
		}
		// Check for matching Email
		Map<String, Account> mapEmailAccount = new Map<String, Account>();
		for(Account account:[select id, PersonEmail, Email_indexed__c from Account 
								where Email_indexed__c in :setEmails and 
								Id not in :setRecordIds limit 1000])
		{
			mapEmailAccount.put(account.PersonEmail, account);	
		}
		// Check for matching Mobile Phone
		Map<String, Account> mapMobilePhoneAccount = new Map<String, Account>();
		String strMobileQuery = '';
		if(setMobilePhones.size()>0)
		{
			strMobileQuery = 'select id, PersonMobilePhone, Mobile_indexed__c from Account where (';
			for(String strMobilePhone:setMobilePhones)
			{
				strMobileQuery += 'Mobile_indexed__c like \'%'+strMobilePhone+'%\' or ';
			}	
			if(strMobileQuery.lastIndexOf(' or ') != -1)
			{	
				strMobileQuery = strMobileQuery.substring(0, strMobileQuery.lastIndexOf(' or '));
			}
			if(setRecordIds.size()>0)
			{		
				strMobileQuery += ') and Id not in (';
				for(String strRecordId:setRecordIds)
				{
					strMobileQuery += '\''+strRecordId+'\', ';
				}	
				if(strMobileQuery.lastIndexOf(', ') != -1)
				{	
					strMobileQuery = strMobileQuery.substring(0, strMobileQuery.lastIndexOf(', '));
				}
				strMobileQuery += ')';	
			}
			else
			{
				if(strMobileQuery.indexOf('(') != -1)
				{
					strMobileQuery = strMobileQuery.replace('(', '');
				}
			}			
			strMobileQuery += ' limit 1000';			
			System.debug('Mobile Query: '+ strMobileQuery);	
			List<Account> listMatchingMobileAccounts = new List<Account>();
			listMatchingMobileAccounts = Database.query(strMobileQuery);
			if(listMatchingMobileAccounts.size()>0)
			{
				for(Account account:listMatchingMobileAccounts)
				{
					mapMobilePhoneAccount.put(account.Mobile_indexed__c, account);
				}
			}
		}		
		// Check for matching Phone
		Map<String, Account> mapPhoneAccount = new Map<String, Account>();
		String strPhoneQuery = '';
		if(setPhones.size()>0)
		{
			strPhoneQuery = 'select id, Phone, Phone_indexed__c from Account where (';
			for(String strPhone:setPhones)
			{
				strPhoneQuery += 'Phone_indexed__c like \'%'+strPhone+'%\' or ';
			}	
			if(strPhoneQuery.lastIndexOf(' or ') != -1)
			{	
				strPhoneQuery = strPhoneQuery.substring(0, strPhoneQuery.lastIndexOf(' or '));
			}	
			if(setRecordIds.size()>0)
			{		
				strPhoneQuery += ') and Id not in (';
				for(String strRecordId:setRecordIds)
				{
					strPhoneQuery += '\''+strRecordId+'\', ';
				}	
				if(strPhoneQuery.lastIndexOf(', ') != -1)
				{	
					strPhoneQuery = strPhoneQuery.substring(0, strPhoneQuery.lastIndexOf(', '));
				}
				strPhoneQuery += ')';	
			}
			else
			{
				if(strPhoneQuery.indexOf('(') != -1)
				{
					strPhoneQuery = strPhoneQuery.replace('(', '');
				}
			}			
			strPhoneQuery += ' limit 1000';	
			List<Account> listMatchingPhoneAccounts = new List<Account>();
			listMatchingPhoneAccounts = Database.query(strPhoneQuery);
			if(listMatchingPhoneAccounts.size()>0)
			{
				for(Account account:listMatchingPhoneAccounts)
				{
					mapPhoneAccount.put(account.Phone_indexed__c, account);
				}
			}
		} 
		// Filter duplicates
		for(Account account:listNewAccounts)
		{							
			String strMatchingIndexKey = '';
			Boolean bMatchFound = false;
			// Email
			if(mapEmailAccount.containsKey(account.Email_indexed__c))
			{
				account.Duplicate__c = true;
				account.Duplicate_Reason__c = 'Email match Id: ' + mapEmailAccount.get(account.Email_indexed__c).Id;
				bMatchFound = true;				
			}
			// Phone
			strMatchingIndexKey = '';
			for(String strKey:mapPhoneAccount.keySet())
			{
				if(strKey != null && account.Phone_indexed__c != null && strKey.contains(account.Phone_indexed__c))
				{
					if(account.Id == null || account.Id != mapPhoneAccount.get(strKey).Id)
					{					
						account.Duplicate__c = true;
						account.Duplicate_Reason__c = 'Phone match Id: ' + mapPhoneAccount.get(strKey).Id;
						bMatchFound = true;	
						break;					
					}																			
				}
			}
			// Mobile
			strMatchingIndexKey = '';			
			for(String strKey:mapMobilePhoneAccount.keySet())
			{
				if(strKey != null && account.Mobile_indexed__c!= null && strKey.contains(account.Mobile_indexed__c))
				{
					if(account.Id == null || account.Id != mapMobilePhoneAccount.get(strKey).Id)
					{					
						account.Duplicate__c = true;
						account.Duplicate_Reason__c = 'Mobile Phone match Id: ' + mapMobilePhoneAccount.get(strKey).Id;
						bMatchFound = true;	
						break;					
					}									
				}			
			}						
			if( bIsApexTest ||
			(!bMatchFound && account!= null 
			&& !(account.Duplicate__c == true && 
			(account.Duplicate_Reason__c != null && account.Duplicate_Reason__c.contains('Address Match with Id'))
			)))
			{
				account.Duplicate__c = false;
				account.Duplicate_Reason__c = '';				
			}
		}	
	}
}